package com.baidu.disconf.core.common.zookeeper;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.baidu.disconf.core.common.utils.ZooUtils;
import com.baidu.disconf.core.common.zookeeper.inner.ResilientActiveKeyValueStore;
import com.gitee.hermer.engine.jars.app.sdk.EngineAppClassLoader;

/**
 * ZK缁熶竴绠＄悊鍣�
 *
 * @author liaoqiqi
 * @version 2014-7-7
 */
public class ZookeeperMgr {

	protected static final Logger LOGGER = LoggerFactory.getLogger(ZookeeperMgr.class);

	private static volatile ResilientActiveKeyValueStore store;

	private String curHost = "";
	private String curDefaultPrefixString = "";

	/**
	 * @return void
	 *
	 * @throws Exception
	 * @Description: 鍒濆鍖�
	 * @author liaoqiqi
	 * @date 2013-6-14
	 */
	public void init(String host, String defaultPrefixString, boolean debug) throws Exception {

		try {

			initInternal(host, defaultPrefixString, debug);

			LOGGER.debug("ZookeeperMgr init.");

		} catch (Exception e) {

			throw new Exception("zookeeper init failed. ", e);
		}
	}

	/**
	 * 寤虹珛杩炴帴
	 */
	private ZookeeperMgr() {

	}



	protected static ConcurrentHashMap<ClassLoader,ZookeeperMgr> ZOOKEEPERS = new ConcurrentHashMap<>();

	public static ZookeeperMgr getInstance() {
		synchronized (ZOOKEEPERS) {
			ClassLoader key = Thread.currentThread().getContextClassLoader();
			synchronized (key) {
				if(ZOOKEEPERS.containsKey(key))
					return ZOOKEEPERS.get(key);
				ZookeeperMgr value = new ZookeeperMgr();
				ZOOKEEPERS.put(key, value);
				return value;
			}
		}
	}

	/**
	 * 閲嶆柊杩炴帴
	 */
	public void reconnect() {
		store.reconnect();
	}

	/**
	 * @return void
	 *
	 * @throws IOException
	 * @throws InterruptedException
	 * @Description: 鍒濆鍖�
	 * @author liaoqiqi
	 * @date 2013-6-14
	 */
	private void initInternal(String hosts, String defaultPrefixString, boolean debug)
			throws IOException, InterruptedException {

		curHost = hosts;
		curDefaultPrefixString = defaultPrefixString;
		if(store == null){
			store = new ResilientActiveKeyValueStore(debug);
			store.connect(hosts);
		}
		LOGGER.info("zoo prefix: " + defaultPrefixString);
		makeDir(defaultPrefixString, ZooUtils.getIp());
	}

	/**
	 * Zoo鐨勬柊寤虹洰褰�
	 *
	 * @param dir
	 */
	public void makeDir(String dir, String data) {
		try {
			boolean deafult_path_exist = store.exists(dir);
			if (!deafult_path_exist) {
				LOGGER.info("create: " + dir);
				this.writePersistentUrl(dir, data);
			} else {
			}

		} catch (KeeperException e) {

			LOGGER.error("cannot create path: " + dir, e);

		} catch (Exception e) {

			LOGGER.error("cannot create path: " + dir, e);
		}
	}

	/**
	 * @return void
	 *
	 * @Description: 搴旂敤绋嬪簭蹇呴』璋冪敤瀹冩潵閲婃斁zookeeper璧勬簮
	 * @author liaoqiqi
	 * @date 2013-6-14
	 */
	public void release() throws InterruptedException {
		if(!(Thread.currentThread().getContextClassLoader() instanceof EngineAppClassLoader))
			store.close();
		else{
			ZOOKEEPERS.remove(Thread.currentThread().getContextClassLoader());
		}
	}

	/**
	 * @return List<String>
	 *
	 * @Description: 鑾峰彇瀛愬瀛� 鍒楄〃
	 * @author liaoqiqi
	 * @date 2013-6-14
	 */
	public List<String> getRootChildren() {

		return store.getRootChildren();
	}

	/**
	 * @return List<String>
	 *
	 * @Description: 鍐欐寔涔呭寲缁撶偣, 娌℃湁鍒欐柊寤�, 瀛樺湪鍒欒繘琛屾洿鏂�
	 * @author liaoqiqi
	 * @date 2013-6-14
	 */
	public void writePersistentUrl(String url, String value) throws Exception {

		store.write(url, value);
	}

	/**
	 * @return List<String>
	 *
	 * @Description: 璇荤粨鐐规暟鎹�
	 * @author liaoqiqi
	 * @date 2013-6-14
	 */
	public String readUrl(String url, Watcher watcher) throws Exception {

		return store.read(url, watcher, null);
	}

	/*
	 * 杩斿洖zk
	 */
	public ZooKeeper getZk() {

		return store.getZk();
	}

	/*
	 * 璺緞鏄惁瀛樺湪
	 */
	public boolean exists(String path) throws Exception {

		return store.exists(path);
	}

	/*
	 * 鐢熸垚涓�涓复鏃剁粨鐐�
	 */
	public String createEphemeralNode(String path, String value, CreateMode createMode) throws Exception {

		return store.createEphemeralNode(path, value, createMode);
	}

	/**
	 * @param path
	 * @param watcher
	 * @param stat
	 *
	 * @return String
	 *
	 * @throws InterruptedException
	 * @throws KeeperException
	 * @Description: 甯︾姸鎬佷俊鎭殑璇诲彇鏁版嵁
	 * @author liaoqiqi
	 * @date 2013-6-17
	 */
	public String read(String path, Watcher watcher, Stat stat) throws InterruptedException, KeeperException {

		return store.read(path, watcher, stat);
	}

	/**
	 * @param path
	 *
	 * @return void
	 *
	 * @Description: 鍒犻櫎缁撶偣
	 * @author liaoqiqi
	 * @date 2013-6-17
	 */
	public void deleteNode(String path) {

		store.deleteNode(path);
	}
}
